pub struct BitsQueueU8 {
    container: u8,
    cur_size: u8
}

pub struct FilledValIter<'a> {
    val: u32,
    remainning: u8,
    only_emit_full: bool,
    queue: &'a mut BitsQueueU8
}

impl Iterator for FilledValIter<'_> {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remainning == 0 {
            return None;
        }

        let free_slots = 8 - self.queue.cur_size;
        let will_be_full = self.remainning >= free_slots;
        let n = if will_be_full { free_slots } else { self.remainning };
            
        self.queue.container |= (self.val >> (32 - free_slots)) as u8;
        self.queue.cur_size += n;

        self.val <<= n;
        self.remainning -= n;

        if !will_be_full && self.only_emit_full {
            None
        } else {
            let val = self.queue.container;
            self.queue.container = 0;
            self.queue.cur_size = 0;
            Some(val)
        }
    }
}

impl BitsQueueU8 {
    pub fn new() -> Self {
        BitsQueueU8 { 
            container: 0, 
            cur_size: 0
        }
    }

    pub fn fill_iter(&mut self, val: u32, len: u8, only_emit_full: bool) -> FilledValIter {
        FilledValIter { val: val << (32 - len), remainning: len, queue: self, only_emit_full }
    }

    #[inline]
    pub fn fill_with(&mut self, val: u8) {
        self.container = val;
        self.cur_size = 8;
    }

    #[inline]
    pub fn size(&self) -> u8 {
        self.cur_size
    }

    #[inline]
    pub fn val(&self) -> u8 {
        self.container
    }

    pub fn clear(&mut self) {
        self.container = 0;
        self.cur_size = 0;
    }

    pub fn push_last_n_bits_of(&mut self, n: u8, val: u8) -> u8 {
        if n == 0 { return 0 }
        let clean_mask = val << (8 - n) >> (8 - n);
        let space = 8 - self.cur_size;
        let remain = n as i16 - space as i16;

        let d = if remain > 0 {
            self.container |= clean_mask >> remain;
            space
        } else {
            self.container |= clean_mask << (-remain);
            n
        };

        self.cur_size += d;
        d
    }

    pub fn push_first_n_bits_of(&mut self, n: u8, val: u8) -> u8 {
        if n == 0 { return 0 }
        let clean_mask = val >> (8 - n) << (8 - n);
        self.container |= clean_mask >> self.cur_size;

        let d = u8::min(n, 8 - self.cur_size);
        self.cur_size += d;
        d
    }

    #[inline]
    pub fn peek(&self) -> Option<u8> {
        if self.cur_size < 1 {
            None
        } else {
            /* (u16::from_be_bytes([0xF, self.container]) << 1).to_be_bytes()[1] */
            Some((self.container & (1 << 7)) >> 7)
        }
    }

    pub fn pull(&mut self, n: u8) -> Option<u8> {
        if n < 1 || n > 8 || self.cur_size < n {
            None
        } else if n == 8 {
            let val = self.container;
            self.container = 0;
            self.cur_size = 0;
            Some(val)
        } else {
            let peek = self.container >> (8 - n);
            self.container <<= n;
            self.cur_size -= n;
            Some(peek)
        }
    }

    pub fn pull_unchecked(&mut self, n: u8) -> u8 {
        if n == 8 {
            let val = self.container;
            self.container = 0;
            self.cur_size = 0;
            val
        } else {
            let val = self.container >> (8 - n);
            self.container <<= n;
            self.cur_size -= n;
            val
        }
    }

}

pub struct BitsQueueU64 {
    container: u64,
    cur_size: u8
}

impl BitsQueueU64 {
    pub fn new() -> Self {
        Self { container: 0u64, cur_size: 0u8 }
    }

    #[inline]
    pub fn fill_with_first_x_byte_of_8(&mut self, x: u8, buf: &[u8;8]) {
        self.container = u64::from_be_bytes(*buf);
        self.cur_size = x << 3;
    }

    #[inline]
    pub fn size(&self) -> u8 {
        self.cur_size
    }

    #[inline]
    pub fn pull_unchecked(&mut self, n: u8) -> u64 {
        if n == 64 {
            let val = self.container;
            self.container = 0;
            self.cur_size = 0;
            val
        } else {
            let val = self.container >> (64 - n);
            self.container <<= n;
            self.cur_size -= n;
            val
        }
    }
}

pub struct BitsQueueU128 {
    container: u128,
    cur_size: u8
}

impl BitsQueueU128 {
    pub fn new() -> Self {
        BitsQueueU128 { container: 0u128, cur_size: 0u8 }
    }

    #[inline(always)]
    pub fn size(&self) -> u8 {
        self.cur_size
    }
    
    #[inline(always)]
    pub fn fill_with_first_x_byte_of_16(&mut self, x: u8, buf: &[u8;16]) {
        self.container = u128::from_be_bytes(*buf);
        self.cur_size = x << 3;
    }

    #[inline(always)]
    pub fn pull_unchecked(&mut self, n: u8) -> u128 {
        if n == 128 {
            let val = self.container;
            self.container = 0;
            self.cur_size = 0;
            val
        } else {
            let val = self.container >> (128 - n);
            self.container <<= n;
            self.cur_size -= n;
            val
        }
    }
}